package net.entelijan.cobean.tree;

import java.awt.Component;
import java.util.List;

import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import net.entelijan.cobean.core.IInitializer;
import net.entelijan.cobean.core.ISingleSelectionListCobean;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ListTreeInitializer extends
		AbstractTreeInitializer implements
		IInitializer<ISingleSelectionListCobean<Object>> {

	private static Log log = LogFactory
			.getLog(ListTreeInitializer.class);

	private ITreeLevelDescription treeLevelDescription;

	public ListTreeInitializer() {
		super();
	}

	@Override
	public ISingleSelectionListCobean<Object> initialize() {
		commonInit();

		return new ISingleSelectionListCobean<Object>() {

			private RootElement value;

			private TreeState treeState = new TreeState();

			private Object selectedValue;

			@Override
			public Object getSelectedValue() {
				return ((CobeanTreeNode)selectedValue).getModel();
			}

			@Override
			public void setSelectedValue(Object selectedValue) {
				log.info("[setSelectedValue] value='" + selectedValue + "'");
				TreePath selectionPath = createTreePath(selectedValue);
				coTree.setSelectionPath(selectionPath);
				coTree.scrollPathToVisible(selectionPath);
			}

			@Override
			public List<Object> getValue() {
				return (List<Object>) this.value.getChildren();
			}

			@Override
			public void setValue(List<Object> value) {
				RootElement root = new RootElement(value);
				this.value = root;
				TreeModel treeModel = createTreeModel(root,
						treeLevelDescription);
				coTree.setCellRenderer(new CobeanTreeCellRenderer());
				treeState.restore(treeModel);
				treeModel.addTreeModelListener(treeState);
				coTree.setModel(treeModel);
				coTree.getSelectionModel().setSelectionMode(
						TreeSelectionModel.SINGLE_TREE_SELECTION);
				coTree.setRootVisible(false);
				coTree.addTreeSelectionListener(new TreeSelectionListener() {

					@Override
					public void valueChanged(TreeSelectionEvent e) {
						TreePath path = e.getPath();
						selectedValue = (Object) path.getLastPathComponent();
					}

				});
			}

		};
	}

	public ITreeLevelDescription getTreeLevelDescription() {
		return treeLevelDescription;
	}

	public void setTreeLevelDescription(
			ITreeLevelDescription treeLevelDescription) {
		RootTreeLevelDescription rootDesc = new RootTreeLevelDescription(
				treeLevelDescription);
		this.treeLevelDescription = rootDesc;
	}

	private static class RootElement {

		private List<Object> children;

		public RootElement(List<Object> children) {
			super();
			this.children = children;
		}

		public List<Object> getChildren() {
			return children;
		}

	}

	private static class RootTreeLevelDescription implements
			ITreeLevelDescription {

		private ITreeLevelDescription childDescription;

		@Override
		public ITreeLevelDescription getChildDescription() {
			return childDescription;
		}

		public RootTreeLevelDescription(ITreeLevelDescription childDescription) {
			super();
			this.childDescription = childDescription;
		}

		@SuppressWarnings("unchecked")
		@Override
		public <T> List<T> getChildren(T object) {
			return (List<T>) ((RootElement) object).getChildren();
		}

		@Override
		public Component getTreeCellRendererComponent(Object model,
				DefaultTreeCellRenderer defaultComp, boolean sel,
				boolean expanded, boolean leaf, int row, boolean hasFocus) {
			return defaultComp;
		}

	}

}
